//
//  HD_NKM_MapView.m
//  HDWuDaDaoServiceCenter
//
//  Created by HDNiuKuiming on 2017/5/16.
//  Copyright © 2017年 HDNiuKuiming. All rights reserved.
//

#import "HD_NKM_MapView.h"
#import "HDTiledView.h"
#import "HDAnnotationView.h"
#import "HD_NKM_MapView+Download.h"
#import "HD_LD_ClusterManager.h"
#import "HD_LD_ClusterAnnotion.h"
#define kStandardUIScrollViewAnimationTime (int64_t)0.10
@interface HD_NKM_MapView ()<HDTiledViewDelegate,UIGestureRecognizerDelegate>{
    NSMutableArray *_annotions;
}

@property (nonatomic, strong) UITapGestureRecognizer *singleTapGestureRecognizer;
@property (nonatomic, strong) UITapGestureRecognizer *doubleTapGestureRecognizer;
@property (nonatomic, strong) UITapGestureRecognizer *twoFingerTapGestureRecognizer;
@property (nonatomic, assign) BOOL muteAnnotationUpdates; // 延迟执行，双击和单点手势作区分

@property (nonatomic, strong) UIImageView      *routeImageView; // 推荐路线
@property (nonatomic, strong) HDAnnotationView *successiveAnn; // 连续定位图标
@property (nonatomic, strong) HDTiledView      *tiledView;
@property (nonatomic, strong) UIImageView      *bgImgView; // 瓦片加载之前，先加载一个背景小图，防止瓦片在线加载时候的频繁闪屏问题
@property (nonatomic,strong) HD_LD_ClusterManager *clusterManager;
@property (nonatomic,strong) NSMutableArray *clusterCaches;
@end


@implementation HD_NKM_MapView

#pragma mark
#pragma mark --------- Init Methods --------

+ (Class)tiledLayerClass
{
    return [HDTiledView class];
}

- (instancetype)initWithFrame:(CGRect)frame contentSize:(CGSize)contentSize
{
    self = [super initWithFrame:frame];

    if (self) {
        self.autoresizingMask  = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        self.delegate          = self;
        self.backgroundColor   = [UIColor clearColor];
        self.contentSize       = contentSize;
        self.bouncesZoom       = YES;
        self.bounces           = NO;
        
        self.minimumZoomScale  = 1.0;
        self.levelsOfZoom      = 3;
        _zoomsInOnDoubleTap     = YES;
        _zoomsOutOnTwoFingerTap = YES;
        _centerSingleTap        = YES;
        _orignalSize           = contentSize;
        _successiveAnn         = nil;
        
        [self subViewInit];
        [self gestureInit];
        
        _mapItemSet = [NSMutableSet new]; // 用于存放未下载的瓦片路径
    }
    
    return self;
}

- (void)subViewInit
{
    _bgImgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0,self.contentSize.width, self.contentSize.height)];
    [self addSubview:_bgImgView];
    
    _tiledView = [[[[self class] tiledLayerClass] alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.contentSize.width, self.contentSize.height)];
    LOG(@"W%f:H%f",self.contentSize.width,self.contentSize.height);
    
    _tiledView.delegate = self;
    [self addSubview:_tiledView];
}

- (void)gestureInit
{
    _singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(singleTapReceived:)];
    _singleTapGestureRecognizer.numberOfTapsRequired = 1;
    [_tiledView addGestureRecognizer:_singleTapGestureRecognizer];
    
    _doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(doubleTapReceived:)];
    _doubleTapGestureRecognizer.numberOfTapsRequired = 2;
    [_tiledView addGestureRecognizer:_doubleTapGestureRecognizer];
    
    [_singleTapGestureRecognizer requireGestureRecognizerToFail:_doubleTapGestureRecognizer];
    
    _twoFingerTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                             action:@selector(twoFingerTapReceived:)];
    _twoFingerTapGestureRecognizer.numberOfTouchesRequired = 2;
    _twoFingerTapGestureRecognizer.numberOfTapsRequired = 1;
    [_tiledView addGestureRecognizer:_twoFingerTapGestureRecognizer];
}


- (void)initRouteImage:(NSString *)imagePath
{
    if (imagePath.length < 1) {
        NSLog(@"imagePath Parameter error!!!");
    }
    else {
        self.routeImageView = [UIImageView new];
        _routeImageView.image = [UIImage imageWithContentsOfFile:imagePath];
        [_routeImageView setFrame:CGRectMake(0, 0, self.contentSize.width, self.contentSize.height)];
        _routeImageView.userInteractionEnabled = YES;
        [self addSubview:_routeImageView];
    }
}

- (void)initMinMapImage:(NSString *)imagePath;
{
    if(imagePath.length > 5)
    [_bgImgView sd_setImageWithURL:[NSURL URLWithString:imagePath]];
}

#pragma mark
#pragma mark -------- UIScrolViewDelegate --------

- (UIView *)viewForZoomingInScrollView:(__unused UIScrollView *)scrollView
{
    return self.tiledView;
}

- (void)scrollViewDidZoom:(__unused UIScrollView *)scrollView
{
    if ([self.mapViewdelegate respondsToSelector:@selector(mapViewDidZoom:)]) {
        [self.mapViewdelegate mapViewDidZoom:self];
    }
    
    for (CAShapeLayer *layer in self.layer.sublayers) {
        if ([layer isKindOfClass:[CAShapeLayer class]]) {
            layer.frame = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
        }
    }
    _routeImageView.frame = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
    _bgImgView.frame = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
    
}

- (void)scrollViewDidScroll:(__unused UIScrollView *)scrollView
{}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    [self startDownloadItem];
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
{
    [self startDownloadItem];
    
    [self updateClusters];
}

#pragma mark
#pragma mark -------- Gesture Suport --------

- (void)singleTapReceived:(UITapGestureRecognizer *)gestureRecognizer
{
    if (_centerSingleTap) {
        [self setContentCenter:[gestureRecognizer locationInView:_tiledView]
                      animated:YES];
    }
    
    if ([self.mapViewdelegate respondsToSelector:@selector(mapView:didReceiveSingleTap:)]) {
        [self.mapViewdelegate mapView:self
                  didReceiveSingleTap:gestureRecognizer];
    }
}

- (void)doubleTapReceived:(UITapGestureRecognizer *)gestureRecognizer
{
    if (self.zoomScale >= self.maximumZoomScale) {
        [self setZoomScale:1.0f animated:YES];
        return;
    }
    
    if (_zoomsInOnDoubleTap) {
        CGFloat newZoom = MIN(powf(2, (log2f(self.zoomScale) + 1.0f)), self.maximumZoomScale); //zoom in one level of detail
        
        self.muteAnnotationUpdates = YES;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, kStandardUIScrollViewAnimationTime * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self setMuteAnnotationUpdates:NO];
        });
        
        [self setZoomScale:newZoom animated:YES];
    }
    
    if ([self.mapViewdelegate respondsToSelector:@selector(mapView:didReceiveDoubleTap:)]) {
        [self.mapViewdelegate mapView:self
                  didReceiveDoubleTap:gestureRecognizer];
    }
    
    for (CAShapeLayer *layer in self.layer.sublayers) {
        if ([layer isKindOfClass:[CAShapeLayer class]]) {
            layer.frame = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
        }
    }
    
    _routeImageView.frame = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
    _bgImgView.frame = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
    
    [self updateClusters];
}

- (void)twoFingerTapReceived:(UITapGestureRecognizer *)gestureRecognizer
{
    if (_zoomsOutOnTwoFingerTap) {
        CGFloat newZoom = MAX(powf(2, (log2f(self.zoomScale) - 1.0f)), self.minimumZoomScale); //zoom out one level of detail
        
        self.muteAnnotationUpdates = YES;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, kStandardUIScrollViewAnimationTime * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self setMuteAnnotationUpdates:NO];
        });
        
        [self setZoomScale:newZoom animated:YES];
    }
    
    if ([self.mapViewdelegate respondsToSelector:@selector(mapView:didReceiveTwoFingerTap:)]) {
        [self.mapViewdelegate mapView:self
               didReceiveTwoFingerTap:gestureRecognizer];
    }
}

// 刷新时机，需要在当前批次瓦片全部下载结束后刷新当前页面
- (void)reloadViewAction
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [_tiledView setNeedsDisplay];
        [_tiledView setNeedsLayout];
    });
}

- (void)changeMorePin:(NSInteger)number // 多个点的情况
{
    HDAnnotationView *firstAnn = nil;
    for (int i = 0; i< [[self subviews] count]; i++)
    {
        UIView *view = [[self subviews]objectAtIndex:i];
        if ([view isKindOfClass:[HDAnnotationView class]])
        {
            HDAnnotationView *temp = (HDAnnotationView *)view;
            if (temp.annotation.beaconNum == number) {
                [temp bigPicture];
                
                if (firstAnn == nil)
                    firstAnn = temp;
            }
            else {
                [temp smallPicture];
            }
        }
    }
    
    if (firstAnn != nil) {
        [self setZoomScale:self.maximumZoomScale animated:YES];
        CGPoint pointToMove = CGPointMake(firstAnn.annotation.point.x/self.minimumZoomScale, firstAnn.annotation.point.y/self.minimumZoomScale);
        [self setContentCenter:pointToMove animated:YES];
    }
}

#pragma mark - HDMapView


- (void)setLevelsOfZoom:(size_t)levelsOfZoom
{
    _levelsOfZoom = levelsOfZoom;
    self.maximumZoomScale = (CGFloat)powf(2.0f, MAX(0.0f, levelsOfZoom));
}

- (void)setLevelsOfDetail:(size_t)levelsOfDetail
{
    if (levelsOfDetail == 1) NSLog(@"Note: Setting levelsOfDetail to 1 causes strange behaviour");
    
    _levelsOfDetail = levelsOfDetail;
    [self.tiledView setNumberOfZoomLevels:levelsOfDetail];
}

- (void)setContentCenter:(CGPoint)center animated:(BOOL)animated
{
    CGPoint new_contentOffset = self.contentOffset;
    
    if (self.contentSize.width > self.bounds.size.width) {
        new_contentOffset.x = MAX(0.0f, (center.x * self.zoomScale) - (self.bounds.size.width / 2.0f));
        new_contentOffset.x = MIN(new_contentOffset.x, (self.contentSize.width - self.bounds.size.width));
    }
    
    if (self.contentSize.height > self.bounds.size.height) {
        new_contentOffset.y = MAX(0.0f, (center.y * self.zoomScale) - (self.bounds.size.height / 2.0f));
        new_contentOffset.y = MIN(new_contentOffset.y, (self.contentSize.height - self.bounds.size.height));
    }
    
    [self setContentOffset:new_contentOffset animated:animated];
}

- (void)addAnnotation:(HDAnnotation *)annotation animated:(BOOL)animate {
    HDAnnotationView *pinAnnotation = [[HDAnnotationView alloc] initWithAnnotation:annotation
                                                                            onView:self
                                                                          animated:animate];
    
    
    if (!_pinAnnotations) {
        _pinAnnotations = [[NSMutableArray alloc] init];
    }
    
    [self.pinAnnotations addObject:pinAnnotation];
    [self addObserver:pinAnnotation
           forKeyPath:@"contentSize"
              options:NSKeyValueObservingOptionNew
              context:nil];
}

- (void)addSuccsiveAnnotation:(HDAnnotation *)annotation animated:(BOOL)animate {
    if (self.zoomScale < self.maximumZoomScale/2)
        [self setZoomScale:self.maximumZoomScale/2 animated:YES];
    
    HDAnnotationView *pinAnnotation = [[HDAnnotationView alloc] initWithAnnotation:annotation
                                                                            onView:self
                                                                          animated:animate];
    
    if (!_pinAnnotations) {
        _pinAnnotations = [[NSMutableArray alloc] init];
    }
    
    if (self.successiveAnn != nil && self.zooming == NO) {
        CGRect frame = _successiveAnn.frame;
        CGRect frameA = pinAnnotation.frame;
        CGPoint nowPoint = CGPointMake(pinAnnotation.annotation.point.x*self.minimumZoomScale/self.zoomScale, pinAnnotation.annotation.point.y*self.minimumZoomScale/self.zoomScale);
        [pinAnnotation removeFromSuperview];
        
        _successiveAnn.hidden = NO;
        _successiveAnn.annotation.point = nowPoint;
        
        [UIView animateWithDuration:2.0f animations:^{
            _successiveAnn.frame = CGRectMake(frameA.origin.x, frameA.origin.y, frame.size.width, frame.size.height);
        }];
    }
    
    else {
        self.successiveAnn = pinAnnotation;
        [self.pinAnnotations addObject:self.successiveAnn];
        [self addObserver:pinAnnotation
               forKeyPath:@"contentSize"
                  options:NSKeyValueObservingOptionNew
                  context:nil];
    }
}

- (void)addAnnotations:(NSArray *)annotations animated:(BOOL)animate
{
    
    for (HDAnnotation *annotation in annotations) {
        [self addAnnotation:annotation animated:animate];
    }
}

- (void)centeredSuccessiveLocation:(CGPoint)centerPoint
{
    if (_successiveAnn != nil) {
        [self setContentCenter:CGPointMake(centerPoint.x/self.zoomScale, centerPoint.y/self.zoomScale) animated:YES];
    }
}

- (void)moveToPlayerCenter:(NSString *)identifier
{
    for (HDAnnotationView *pin in self.pinAnnotations) {
        if ([pin.annotation.identify isEqualToString:identifier]) {
            CGPoint pointToMove = CGPointMake(pin.annotation.point.x/self.minimumZoomScale, pin.annotation.point.y/self.minimumZoomScale);
            [self setContentCenter:pointToMove animated:YES];
            break;
        }
    }
}

- (IBAction)showCallOut:(id)sender
{
    if (_isShowCallOutView == NO) { // 点击POI后直接进入播放
        for (HDAnnotationView *pin in self.pinAnnotations) {
            if (pin == sender) {
                CGPoint pointToMove = CGPointMake(pin.annotation.point.x/self.minimumZoomScale, pin.annotation.point.y/self.minimumZoomScale);
                [self setContentCenter:pointToMove animated:YES];
                [[NSNotificationCenter defaultCenter] postNotificationName:Map_POI_Push_To_Player object:pin.annotation];
                break;
            }
        }
    }
    
    else { // 点击POI后显示callout
        HDAnnotationView *pin = nil;
        for (HDAnnotationView *pinTemp in self.pinAnnotations) {
            if (pinTemp == sender) {
                pin = pinTemp;
                break;
            }
        }
        
        if (!self.callout) {
            // create the callout
            HDCallOutView * calloutView = [[HDCallOutView alloc] initWithAnnotation:pin.annotation
                                                                              onMap:self];
            self.callout = calloutView;
            
            [self addObserver:self.callout
                   forKeyPath:@"contentSize"
                      options:NSKeyValueObservingOptionNew
                      context:nil];
            [self addSubview:self.callout];
        }
        else {
            [self hideCallOut];
            [self.callout displayAnnotation:pin.annotation];
        }
        
        CGPoint pointToMove = CGPointMake(pin.annotation.point.x/self.minimumZoomScale, pin.annotation.point.y/self.minimumZoomScale);
        [self setContentCenter:pointToMove animated:YES];
    }
}

- (void)hideCallOut
{
    self.callout.hidden = YES;
}

- (void)removeAnnatation:(HDAnnotationView *)annotation animated:(BOOL)animate
{
    [annotation removeFromSuperview];
    [self removeObserver:annotation forKeyPath:@"contentSize"];
}

- (void)removeAllAnnatations:(BOOL)animate
{
    for (HDAnnotationView *annotation in _pinAnnotations) {
        [self removeAnnatation:annotation animated:animate];
    }
    
    [self.pinAnnotations removeAllObjects];
    [self hideCallOut];
//    [self setZoomScale:1 animated:YES];
}

- (void)removeSuccessive:(HDAnnotation *)ann
{
    for (HDAnnotationView *annTemp in _pinAnnotations) {
        if (annTemp.annotation.isPlay == kPlay_Status_Successive) {
            annTemp.hidden = YES;
            [annTemp removeFromSuperview];
        }
    }
}

- (void)smallAllAnnView
{
    for (int i = 0; i< [[self subviews] count]; i++) {
        UIView *view = [[self subviews]objectAtIndex:i];
        if ([view isKindOfClass:[HDAnnotationView class]]) {
            HDAnnotationView *temp = (HDAnnotationView *)view;
            [temp smallPicture];
        }
    }
}

- (void)cleanBeaconAnimate
{
    for (HDAnnotationView *pin in self.pinAnnotations) {
        pin.isAnimating = NO;
    }
}

- (void)cancelZoomAction
{
    self.dataSource = nil;
    self.mapViewdelegate = nil;
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setZoomScale:animated:) object:nil];
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setContentCenter:animated:) object:nil];
}

- (void)changePOIImg:(NSString *)identifier
            withPath:(NSString *)imagePath
{
    for (int i = 0; i< [[self subviews] count]; i++)
    {
        UIView *view = [[self subviews]objectAtIndex:i];
        if ([view isKindOfClass:[HDAnnotationView class]]) {
            HDAnnotationView *temp = (HDAnnotationView *)view;
            if ([temp.annotation.identify isEqualToString:identifier]) {
                [temp changePOIImageWithPath:imagePath];
            }
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (!self.dragging) {
        [self hideCallOut];
    }
    
    [super touchesEnded:touches withEvent:event];
}


#pragma mark - HDTiledViewDelegate

- (UIImage *)tiledView:(__unused HDTiledView *)tiledView
           imageForRow:(NSInteger)row
                column:(NSInteger)column
                 scale:(NSInteger)scale
{
    return [self.dataSource  mapView:self
                         imageForRow:row
                              column:column
                               scale:scale];
}


- (void)showOrHideRouteView:(BOOL)isHide
{
    routeView.hidden = isHide;
}


//聚合当前地图上的POI
- (void)addClusterAnnotions:(NSArray *)annotations{
    if (_annotions == nil) {
        _annotions =[NSMutableArray arrayWithCapacity:annotations.count];
    }
    //向点聚合管理类中添加标注
    /*
     *注意
     *1.由于对地图的ContentSize添加了观察者annotionView,而AnnotionView的坐标有地图的缩放级别和annotion的point决定,
     *因为在聚合算法中会对annotion的point进行计算改变，所以不能把annotion直接添加到_annotions数组里面，否则在聚合算法计算
     *annotion坐标时会对anotionView的坐标产生影响（因为把数组A的元素直接添加到数组B以后，若改变数组B里面的对象内容，数组A也会随之改变）
     */
    HDAnnotation * ann = nil;
    for (NSInteger i = 0; i < annotations.count; i++) {
        HDAnnotation *annotion = annotations[i];
        ann = [HDAnnotation annotationWithPoint:annotion.point];
        ann.originalPoint = annotion.originalPoint;
        ann.identify = annotion.identify;
        [_annotions addObject:ann];
    }
    
    [self updateClusters];
}

//更新聚合状态
- (void)updateClusters{
    
    int minScale = round(self.minimumZoomScale);
    int maxScale = round(self.maximumZoomScale);
    if (_clusterCaches == nil) {
        _clusterCaches = [[NSMutableArray alloc]init];
        for (int i=0; i<maxScale-minScale+1; ++i) {
            [_clusterCaches addObject:[NSMutableArray array]];
        }
    }
    
    if (!_clusterManager) {
        //点聚合管理者
        _clusterManager = [[HD_LD_ClusterManager alloc] init];
        _clusterManager.algorithm.quadtree.rect = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
        //向点聚合管理类中添加标注
        for (NSInteger i = 0; i < _annotions.count; i++) {
            HDAnnotation *annotion = _annotions[i];
            [_clusterManager addClusterItem:annotion];
        }
    }
    
    
    @synchronized (_clusterCaches) {
        //根据当前地图的缩放级别和地图的ContentSize进行点聚合计算
        NSArray *array = [_clusterManager getClusters:self.zoomScale withRect:CGRectMake(0, 0, self.contentSize.width, self.contentSize.height)];
        [self handleVisibleAnnotions:array];

    }
}

- (void)handleVisibleAnnotions:(NSArray *)array{
    NSMutableArray *visibleAnns = [NSMutableArray arrayWithCapacity:0];
    dispatch_async(dispatch_get_main_queue(), ^{
        //将聚合后的标注显示出来，被聚合的标注隐藏掉
        for (HD_LD_ClusterAnnotion *item in array) {
            for (HDAnnotationView *annView in _pinAnnotations) {
                if ([visibleAnns containsObject:annView]) {
                    continue;
                }
                if (![annView.annotation.identify isEqualToString:item.annnotion.identify]) {
                    annView.hidden = YES;
//                    annView.clusterCount = 1;
//                    annView.backgroundColor = [UIColor grayColor];
                }else{
                    annView.clusterCount = item.size;
                    annView.hidden = NO;
                    annView.backgroundColor = [UIColor redColor];
                    [visibleAnns addObject:annView];
                }
            }
            
        }
        
    });
}


-(void)dealloc
{
    _tiledView.delegate = nil;

    if (self.callout) {
        [self removeObserver:self.callout forKeyPath:@"contentSize"];
    }
    
    if (_pinAnnotations) {
        for (HDAnnotation *annotation in _pinAnnotations) {
            [self removeObserver:annotation forKeyPath:@"contentSize"];
        }
    }
    
    // 固定的推荐路线
    if (_routeImageView != nil) {
        [_routeImageView removeFromSuperview];
        self.routeImageView = nil;
    }
    
    // 防止瓦片闪动时候的小地图
    if (_bgImgView != nil) {
        [_bgImgView removeFromSuperview];
        self.bgImgView = nil;
    }
}

@end
